package com.example.pdfprocessor.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

@Service
@Slf4j
public class PdfService {

    @Value("${app.upload.dir}")
    private String uploadDir;

    @Value("${app.temp.dir}")
    private String tempDir;
    
    private File uploadDirFile;
    private File tempDirFile;

    @PostConstruct
    public void init() {
        try {
            log.info("初始化存储目录，配置的上传目录: {}", uploadDir);
            log.info("初始化存储目录，配置的临时目录: {}", tempDir);
            
            // 创建绝对路径
            uploadDirFile = new File(uploadDir);
            tempDirFile = new File(tempDir);
            
            // 创建多级目录
            if (!uploadDirFile.exists()) {
                boolean created = uploadDirFile.mkdirs();
                if (!created) {
                    log.error("无法创建上传目录: {}", uploadDirFile.getAbsolutePath());
                    throw new RuntimeException("无法创建上传目录: " + uploadDirFile.getAbsolutePath());
                }
            }
            
            if (!tempDirFile.exists()) {
                boolean created = tempDirFile.mkdirs();
                if (!created) {
                    log.error("无法创建临时目录: {}", tempDirFile.getAbsolutePath());
                    throw new RuntimeException("无法创建临时目录: " + tempDirFile.getAbsolutePath());
                }
            }
            
            log.info("上传目录创建成功: {}", uploadDirFile.getAbsolutePath());
            log.info("临时目录创建成功: {}", tempDirFile.getAbsolutePath());
            
            // 验证目录是否可写
            if (!uploadDirFile.canWrite()) {
                log.error("上传目录没有写入权限: {}", uploadDirFile.getAbsolutePath());
                throw new RuntimeException("上传目录没有写入权限: " + uploadDirFile.getAbsolutePath());
            }
            
            if (!tempDirFile.canWrite()) {
                log.error("临时目录没有写入权限: {}", tempDirFile.getAbsolutePath());
                throw new RuntimeException("临时目录没有写入权限: " + tempDirFile.getAbsolutePath());
            }
        } catch (Exception e) {
            log.error("初始化存储目录失败", e);
            throw new RuntimeException("无法创建存储目录", e);
        }
    }

    /**
     * 处理上传的PDF文件，去除彩色内容
     * @param file 上传的PDF文件
     * @return 处理后的PDF文件名
     */
    public String processAndSavePdf(MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        log.info("处理文件: {}", originalFilename);
        
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String uniqueFilename = UUID.randomUUID().toString() + fileExtension;
        File inputFile = new File(uploadDirFile, "input_" + uniqueFilename);
        File outputFile = new File(uploadDirFile, uniqueFilename);
        
        log.info("输入文件路径: {}", inputFile.getAbsolutePath());
        log.info("输出文件路径: {}", outputFile.getAbsolutePath());
        
        // 确保目录存在
        if (!inputFile.getParentFile().exists()) {
            boolean created = inputFile.getParentFile().mkdirs();
            if (!created) {
                throw new IOException("无法创建输入文件目录: " + inputFile.getParentFile().getAbsolutePath());
            }
        }
        
        // 保存上传的文件
        try {
            file.transferTo(inputFile);
            if (!inputFile.exists()) {
                throw new IOException("文件保存失败，文件不存在: " + inputFile.getAbsolutePath());
            }
            log.info("文件保存成功: {}", inputFile.getAbsolutePath());
        } catch (IOException e) {
            log.error("保存上传文件失败", e);
            throw new IOException("保存上传文件失败: " + e.getMessage(), e);
        }
        
        // 处理PDF文件
        try (PDDocument document = PDDocument.load(inputFile)) {
            PDDocument outputDocument = new PDDocument();
            
            // 遍历PDF页面
            for (int pageIndex = 0; pageIndex < document.getNumberOfPages(); pageIndex++) {
                PDPage page = document.getPage(pageIndex);
                
                // 渲染为图片
                PDFRenderer renderer = new PDFRenderer(document);
                BufferedImage image = renderer.renderImageWithDPI(pageIndex, 300, ImageType.RGB);
                
                // 处理图片，只保留黑色内容
                BufferedImage processedImage = keepOnlyBlackContent(image);
                
                // 创建新页面
                PDPage newPage = new PDPage(page.getMediaBox());
                outputDocument.addPage(newPage);
                
                // 将处理后的图片放回PDF
                PDImageXObject pdImage = LosslessFactory.createFromImage(outputDocument, processedImage);
                PDPageContentStream contentStream = new PDPageContentStream(outputDocument, newPage);
                
                // 调整图像大小以适应页面
                PDRectangle mediaBox = newPage.getMediaBox();
                contentStream.drawImage(pdImage, 0, 0, mediaBox.getWidth(), mediaBox.getHeight());
                contentStream.close();
            }
            
            // 保存处理后的PDF
            outputDocument.save(outputFile);
            outputDocument.close();
            log.info("PDF处理完成并保存至: {}", outputFile.getAbsolutePath());
        } catch (IOException e) {
            log.error("处理PDF文件失败", e);
            throw new IOException("处理PDF文件失败: " + e.getMessage(), e);
        }
        
        // 删除输入文件
        if (inputFile.exists() && !inputFile.delete()) {
            log.warn("无法删除临时输入文件: {}", inputFile.getAbsolutePath());
        }
        
        return uniqueFilename;
    }
    
    /**
     * 处理图片，只保留黑色内容
     * @param image 原始图片
     * @return 处理后的图片
     */
    private BufferedImage keepOnlyBlackContent(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();
        BufferedImage processedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        
        // 设置白色背景
        Graphics2D g2d = processedImage.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, width, height);
        g2d.dispose();
        
        // 像素级处理
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int rgb = image.getRGB(x, y);
                Color color = new Color(rgb);
                
                // 计算颜色的灰度值
                int grayValue = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
                
                // 判断是否是黑色或接近黑色的颜色（灰度值低）
                // 同时排除明显的彩色（R、G、B差距大）
                int colorVariance = Math.max(Math.abs(color.getRed() - color.getGreen()), 
                                     Math.max(Math.abs(color.getGreen() - color.getBlue()), 
                                             Math.abs(color.getRed() - color.getBlue())));
                
                // 修改阈值，使浅黑色文字也能保留
                // 1. 增加灰度值阈值，使更浅的灰色也能被检测到（从 80 调整到 120）
                // 2. 稍微增加颜色方差阈值（从 30 调整到 40），但仍可以排除彩色内容
                // 3. 对深灰度区域（<80）使用更宽松的颜色方差条件
                if ((grayValue < 120 && colorVariance < 40) || (grayValue < 80 && colorVariance < 60)) {
                    // 保留为黑色
                    processedImage.setRGB(x, y, Color.BLACK.getRGB());
                }
                // 其他颜色已经设置为白色背景，无需处理
            }
        }
        
        return processedImage;
    }
    
    /**
     * 获取处理后的PDF文件
     * @param filename 文件名
     * @return 文件对象
     */
    public File getPdfFile(String filename) {
        return new File(uploadDirFile, filename);
    }
    
    /**
     * 删除PDF文件
     * @param filename 文件名
     */
    public void deletePdfFile(String filename) {
        try {
            File fileToDelete = new File(uploadDirFile, filename);
            if (fileToDelete.exists()) {
                fileToDelete.delete();
            }
        } catch (Exception e) {
            log.error("删除文件失败: {}", filename, e);
        }
    }
} 